home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 398 / 398.xpi / chrome / forecastfox.jar / content / utilities / manager-service.js < prev   
Text File  |  2010-02-04  |  36KB  |  1,278 lines

  1. /*------------------------------------------------------------------------------
  2.   Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
  3.   ----------------------------------------------------------------------------*/
  4.  
  5. /******************************************************************************
  6.  * Timer constants
  7.  *****************************************************************************/
  8. const DEFAULT_DELAY = ONE_SECOND/100;
  9.  
  10. /******************************************************************************
  11.  * Front-end Preference Constants
  12.  *****************************************************************************/ 
  13. const OBSERVER_PREFS = {
  14.   "units.current": true,
  15.   "general.locid": true,
  16.   "general.bar": true,
  17.   "general.position": true,
  18.   "general.last": true,
  19.   "general.delay": true,
  20.   "general.radar": true,
  21.   "radar.panel.enabled": true,
  22.   "radar.panel.display": true,
  23.   "radar.panel.label": true,
  24.   "radar.tooltip.enabled": true,
  25.   "radar.tooltip.display": true,
  26.   "radar.tooltip.title": true,
  27.   "radar.tooltip.label": true,
  28.   "hbh.panel.enabled": true,
  29.   "fiveday.panel.enabled": true,
  30.   "swa.panel.enabled": true,
  31.   "swa.panel.display": true,
  32.   "swa.panel.label": true,
  33.   "swa.tooltip.enabled": true,
  34.   "swa.tooltip.display": true,
  35.   "swa.tooltip.title": true,
  36.   "swa.tooltip.label": true,
  37.   "cc.panel.enabled": true,
  38.   "cc.panel.display": true,
  39.   "cc.panel.label": true,
  40.   "cc.tooltip.enabled": true,
  41.   "cc.tooltip.display": true,
  42.   "cc.tooltip.title": true,
  43.   "cc.tooltip.label": true,
  44.   "dayt.panel.mode": true,
  45.   "dayt.panel.switch": true,
  46.   "dayt.panel.enabled": true,
  47.   "dayt.panel.display": true,
  48.   "dayt.panel.label": true,
  49.   "dayt.tooltip.enabled": true,
  50.   "dayt.tooltip.display": true,
  51.   "dayt.tooltip.title": true,
  52.   "dayt.tooltip.label": true,
  53.   "dayf.panel.mode": true,
  54.   "dayf.panel.days": true,
  55.   "dayf.panel.enabled": true,
  56.   "dayf.panel.display": true,
  57.   "dayf.panel.label": true,
  58.   "dayf.tooltip.enabled": true,
  59.   "dayf.tooltip.display": true,
  60.   "dayf.tooltip.title": true,
  61.   "dayf.tooltip.label": true
  62. };
  63.  
  64. /******************************************************************************
  65.  * Main interface used for interacting with the back-end.  All
  66.  * service requests should go through this interface.
  67.  * 
  68.  * @status    FROZEN
  69.  * @version   1.0
  70.  ******************************************************************************/
  71. function ManagerService() 
  72. {
  73.   //setup additional interfaces
  74.   if (checkAlertService() && "nsIAlertListener" in Ci)
  75.     this._ifaces.push(Ci.nsIAlertListener);
  76.   this._ifaces.push(Ci.nsIObserver);
  77.   this._ifaces.push(Ci.nsISupportsWeakReference);
  78.   this._ifaces.push(Ci.nsIWebProgressListener);
  79.   
  80.   //setup a new error
  81.   this._error = Cc["@ensolis.com/forecastfox/error-item;1"].
  82.                 createInstance(Ci.ffIErrorItem);      
  83. }
  84. ManagerService.prototype = {
  85.   __proto__: new ServiceBase("ManagerService"),
  86.   _obSvc: null,
  87.   _state: "stopped",
  88.   _isUpdating: null,
  89.   _isLoading: null,
  90.   _updateData: null,
  91.   _updateTimer: null,
  92.   _updateRequest: null,
  93.   _updateError: null,
  94.   _radarPersist: null,
  95.   _radarFile: null,
  96.   _errorTimer: null,
  97.   _alertTimer: null,   
  98.   _serializeTimer: null,  
  99.   _partner: "forecastfox",
  100.   _services: null,
  101.   _cacheSvc: null,
  102.   _ioSvc: null,
  103.   
  104.   ///////////////////////////
  105.   // nsIAlertListener
  106.   onAlertFinished: function ManagerService_onAlertFinished(aCookie) 
  107.   {
  108.     //get the icon URL
  109.     var cookie = eval(aCookie);
  110.     var icon = cookie[1];
  111.     if (icon == "")
  112.       return;
  113.       
  114.     //remove entry from cache
  115.     this.evictImage(icon);
  116.   },
  117.   onAlertClickCallback: function ManagerService_onAlertClickCallback(aCookie)
  118.   {
  119.     var cookie = eval(aCookie);
  120.     var where = getPref("links.alert");
  121.     openLink(cookie[1], where);
  122.   },
  123.     
  124.   ///////////////////////////
  125.   // nsIWebProgressListener
  126.   onLocationChange: function ManagerService_onLocationChange(aWebProgress, aRequest, aLocation) {},
  127.   onProgressChange: function ManagerService_onProgressChange(aWebProgress, aRequest, aCurSelfProgress, aXaxSelfProgress, aCurTotalProgress, aMaxTotalProgress ) {},
  128.   onSecurityChange: function ManagerService_onSecurityChange(aWebProgress, aRequest, aState) {},
  129.   onStatusChange: function ManagerService_onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {},
  130.   onStateChange: function ManagerService_onStateChange(aWebProgress, aRequest, aStateFlags, aStatus)
  131.   {
  132.     //only do when state is done
  133.     var stateDone = Ci.nsIWebProgressListener.STATE_STOP;
  134.     if (stateDone != (aStateFlags & stateDone)) 
  135.       return;   
  136.  
  137.     //end the radar update
  138.     this._endRadar();
  139.   },
  140.       
  141.   /////////////////////////////
  142.   // nsIObserver
  143.   observe: function ManagerService_observe(aSubject, aTopic, aData)
  144.   {
  145.     switch (aTopic) {  
  146.     
  147.     //application shutdown 
  148.     case "xpcom-shutdown":
  149.       this._state = null;
  150.       this._obSvc.removeObserver(this, "profile-before-change");
  151.       this._obSvc.removeObserver(this, "xpcom-shutdown");
  152.       this._obSvc = null;
  153.       break;  
  154.     
  155.     //application profile is changing
  156.     case "profile-before-change":
  157.       this.stop();
  158.       break; 
  159.       
  160.     //timer fired
  161.     case "timer-callback":
  162.     
  163.       switch (aSubject) {
  164.  
  165.       //update timer fired
  166.       case this._updateTimer:
  167.         this._startUpdate();
  168.         break;
  169.         
  170.       //alert timer fired
  171.       case this._alertTimer:
  172.         this._startAlert();
  173.         break;
  174.         
  175.       //error timer fired
  176.       case this._errorTimer:
  177.  
  178.         //abort the request
  179.         if (this._updateRequest) {
  180.           this._updateRequest.abort();
  181.           this._updateRequest.onload = null;
  182.           this._updateRequest.onerror = null;
  183.           this._updateRequest = null;
  184.         }
  185.         
  186.         //set the error
  187.         const PREFIX = "ff.manager.timeout.";
  188.         var name = this.bundle.GetStringFromName(PREFIX + "name");
  189.         var message = this.bundle.GetStringFromName(PREFIX + "message");
  190.         this._error.init(SEVERITY_ERROR, name, message);
  191.         
  192.         //finish the update
  193.         this._finishUpdate(false);
  194.         break;
  195.         
  196.       //serialize timer fired
  197.       case this._serializeTimer:
  198.         this._serializeCache();
  199.         break;
  200.       }
  201.       break;
  202.  
  203.       //alert went away by itself
  204.       case "alertfinished":
  205.         this.onAlertFinished(aData);
  206.         break;
  207.  
  208.       //user clicked alert                   
  209.       case "alertclickcallback":
  210.         this.onAlertClickCallback(aData);
  211.         break;
  212.  
  213.       //profile notification
  214.       case "forecastfox-profiles":
  215.       
  216.         //ignore except current and endBatch
  217.         if (aData != "current" && aData !="endBatch")
  218.           return;
  219.           
  220.         //ignore change if it is loading or batch
  221.         if (this.profiles.isLoading || this.profiles.isBatch)
  222.           return;
  223.           
  224.         this._updateData = this._getData();
  225.         this._scheduleTimer(DEFAULT_DELAY);
  226.         break;
  227.       
  228.       //icon notification
  229.       case "forecastfox-icons":
  230.       
  231.         //ignore except current and endBatch
  232.         if (aData != "current" && aData !="endBatch")
  233.           return;
  234.           
  235.         //ignore change if it is loading or batch
  236.         if (this.icons.isLoading || this.icons.isBatch)
  237.           return;
  238.           
  239.         this._updateData = this._getData();
  240.         this._scheduleTimer(DEFAULT_DELAY);
  241.         break;
  242.       
  243.       //preference changed          
  244.       case "nsPref:changed":
  245.       
  246.         //ignore preferences the front-end does not care about
  247.         if (!OBSERVER_PREFS.hasOwnProperty(aData))
  248.           return;
  249.         
  250.         //ignore if profile service loading and not an excluded pref
  251.         if (!EXCLUDED_PREFS.hasOwnProperty(aData) && 
  252.             (this.profiles.isLoading || 
  253.             this.profiles.isBatch))
  254.           return;
  255.                       
  256.         switch (aData) {    
  257.         
  258.         //preference causing us to force an update from the server  
  259.         case "general.locid":
  260.         case "units.current":
  261.  
  262.           this._updateData = this._getData();
  263.           this._updateData["force"] = true;
  264.           this._scheduleTimer(DEFAULT_DELAY);
  265.           break;   
  266.           
  267.         //preferences causing us to reload
  268.         case "general.last":
  269.         case "general.delay":
  270.         case "general.radar":
  271.         case "radar.panel.enabled":          
  272.         
  273.           //ignore if we are setting these prefs
  274.           if (this.isLoading)
  275.             return;
  276.             
  277.           this._updateData = this._getData();
  278.           this._scheduleTimer(DEFAULT_DELAY);
  279.           break;
  280.         
  281.         //all other preference causing the front-end to redisplay
  282.         default:
  283.         
  284.           this._obSvc.notifyObservers(this, "forecastfox-manager", "display");
  285.           break;  
  286.         }            
  287.         break;                 
  288.     }
  289.   },
  290.                    
  291.   ///////////////////////////
  292.   // ffIService
  293.   start: function ManagerService_start()
  294.   {
  295.     //do nothin if already running
  296.     if (this.isRunning)
  297.       return false;
  298.      
  299.     //set state to starting
  300.     this._state = "starting";
  301.     
  302.     //setup variables 
  303.     this._isUpdating = false;
  304.     this._isLoading = false;
  305.     this._updateError = 0;
  306.     this._services = {};    
  307.     this._ioSvc = Cc["@mozilla.org/network/io-service;1"].
  308.                   getService(Ci.nsIIOService);
  309.     this._cacheSvc = Cc["@mozilla.org/image/cache;1"].
  310.                      getService(Ci.imgICache);
  311.       
  312.     //setup timers
  313.     this._updateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  314.     this._errorTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  315.     this._alertTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  316.     this._serializeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  317.     
  318.     //ping server
  319.     this.ping.run();
  320.  
  321.     //make sure we have the profile and icon service started
  322.     var current = this.profiles.current;
  323.     current = this.icons.current;
  324.     
  325.     //setup update data
  326.     this._updateData = this._getData();
  327.       
  328.     //add observers
  329.     this._obSvc = Cc["@mozilla.org/observer-service;1"].
  330.                   getService(Ci.nsIObserverService);
  331.     this._obSvc.addObserver(this, "forecastfox-profiles", true);
  332.     this._obSvc.addObserver(this, "forecastfox-icons", true);
  333.     this._obSvc.addObserver(this, "profile-before-change", true);
  334.     this._obSvc.addObserver(this, "xpcom-shutdown", true);
  335.     
  336.     //add prefernce observer
  337.     var pb2 = this.branch.QueryInterface(Ci.nsIPrefBranchInternal);
  338.     pb2.addObserver("", this, true);
  339.     
  340.     //return success
  341.     this._state = "started";   
  342.     return true; 
  343.   },
  344.   
  345.   stop: function ManagerService_stop()
  346.   {   
  347.     //do nothin if not running
  348.     if (!this.isRunning)
  349.       return;
  350.     
  351.     //set state to stopping
  352.     this._state = "stopping";
  353.     
  354.     //remove preference observers
  355.     var pb2 = this.branch.QueryInterface(Ci.nsIPrefBranchInternal);
  356.     pb2.removeObserver("", this);
  357.     
  358.     //remove notification observers
  359.     if (this._obSvc) {
  360.       this._obSvc.removeObserver(this, "forecastfox-profiles");
  361.       this._obSvc.removeObserver(this, "forecastfox-icons");
  362.     }       
  363.       
  364.     //stops timers and aborts requests
  365.     this._endUpdate();
  366.     
  367.     //stop components
  368.     for (var name in this._services) {
  369.     
  370.       /* do not stop the disk service because other service 
  371.          depend on it in the flushData method */
  372.       if (name == "DiskService")
  373.         continue;
  374.       
  375.       //stop the component
  376.       var contractID = gComponents[name].contractID;
  377.       var interfaceID = gComponents[name].interfaceID;  
  378.       var service = Cc[contractID].getService(interfaceID);
  379.       service.stop();
  380.       delete this._services[name];
  381.     }  
  382.     
  383.     //stop the disk service
  384.     name = "DiskService";
  385.     if (this._services.hasOwnProperty(name)) {
  386.       contractID = gComponents[name].contractID;
  387.       interfaceID = gComponents[name].interfaceID;  
  388.       service = Cc[contractID].getService(interfaceID);
  389.       service.stop();
  390.       delete this._services[name];
  391.     }
  392.     
  393.     //destroy variables    
  394.     this._isUpdating = null;
  395.     this._isLoading = null;
  396.     this._updateData = null;
  397.     this._updateTimer = null;
  398.     this._updateRequest = null;
  399.     this._updateError = null;
  400.     this._radarPersist = null;
  401.     this._radarFile = null;
  402.     this._errorTimer = null;
  403.     this._alertTimer = null; 
  404.     this._serializeTimer = null;    
  405.     this._partner = null;
  406.     this._services = null;
  407.     this._ioSvc = null;
  408.     this._cacheSvc = null;
  409.     
  410.     //set state to stopped
  411.     this._state = "stopped";
  412.   },
  413.              
  414.   ///////////////////////////
  415.   // ffIManagerService  
  416.   
  417.   /**
  418.    * Service is currently running.
  419.    */
  420.   get isRunning() { 
  421.     if (this._state == "starting" ||
  422.         this._state == "started")
  423.       return true;
  424.     return false;
  425.   },
  426.   
  427.   /**
  428.    * Service is updating data.
  429.    */
  430.   get isUpdating() { return this._isUpdating; }, 
  431.   
  432.   /**
  433.    * Service is being loaded into preferences.
  434.    */
  435.   get isLoading() { return this._isLoading; }, 
  436.     
  437.   /**
  438.    * Run an update.  Called from the a dom window.
  439.    *
  440.    * @param   Force the update from the server.
  441.    */
  442.   run: function ManagerService_run(aForce)
  443.   {
  444.     //start the service if it has not been started
  445.     if (!this.isRunning)
  446.       this.start();
  447.                     
  448.     //set the forced attribute
  449.     this._updateData["force"] = aForce;
  450.           
  451.     //schedule an update
  452.     this._scheduleTimer(DEFAULT_DELAY);
  453.   },
  454.  
  455.   /**
  456.    * Open a link in the main application window
  457.    *
  458.    * @param   The url to open.
  459.    * @param   Where to open the link (current, window, tab, tabshifted)
  460.    */ 
  461.    openLink: function ManagerService_openLink(aURL, aWhere)
  462.    {
  463.      openLink(aURL, aWhere);
  464.    },
  465.  
  466.   /**
  467.    * Gets a preference.  
  468.    *
  469.    * @param   Name of the preference to retrieve.
  470.    * @return  Requested preference value. 
  471.    */
  472.    getPref: function ManagerService_getPref(aName)
  473.    {
  474.      return getPref(aName);
  475.    },
  476.  
  477.   /**
  478.    * Sets a preference.  
  479.    *
  480.    * @param   Name of the preference to retrieve.
  481.    * @param   Value to set the preference to.
  482.    */
  483.   setPref: function ManagerService_setPref(aName, aValue)
  484.   {
  485.     setPref(aName, aValue);
  486.   },
  487.  
  488.   /**
  489.    * Evict an image from the cache.
  490.    * 
  491.    * @param   The image URL.
  492.    */
  493.   evictImage: function ManagerService_evictImage(aURL)
  494.   {
  495.     //convert the URL to a URI
  496.     var URI = this._ioSvc.newURI(aURL, null, null);
  497.     
  498.     //evict the image
  499.     try {
  500.       this._cacheSvc.removeEntry(URI);
  501.     } catch(e) {}
  502.   },
  503.   
  504.   /**
  505.    * Partner id used in link parameters.
  506.    */      
  507.   get partner() { return this._partner; },
  508.   
  509.   /**
  510.    * ffIDiskService component.
  511.    */
  512.   get disk() { return this._getService("DiskService"); },
  513.   
  514.   /**
  515.    * ffIPingService component.
  516.    */
  517.   get ping() { return this._getService("PingService"); },
  518.   
  519.   /**
  520.    * ffIConverterService component.
  521.    */
  522.   get converters() { return this._getService("ConverterService"); },
  523.   
  524.   /**
  525.    * ffIParserService component.
  526.    */
  527.   get parser() { return this._getService("ParserService"); },
  528.   
  529.   /**
  530.    * ffIProfileService component.
  531.    */
  532.   get profiles() { return this._getService("ProfileService"); },
  533.   
  534.   /**
  535.    * ffIMigratorService component.
  536.    */
  537.   get migrator() { return this._getService("MigratorService"); },
  538.   
  539.   /**
  540.    * ffIPackService component.
  541.    */
  542.   get icons() { return this._getService("PackService"); },
  543.                   
  544.   ////////////////////////////////
  545.   // Internal Functions
  546.     
  547.   /**
  548.    * Start a data update.
  549.    */ 
  550.   _startUpdate: function ManagerService__startUpdate()
  551.   {
  552.     //end previous update
  553.     this._endUpdate();
  554.             
  555.     //do nothing if location not set
  556.     if (!this._checkID())
  557.       return;   
  558.       
  559.     //mark we are updating
  560.     this._isUpdating = true;
  561.       
  562.     //notify observers of update 
  563.     this._obSvc.notifyObservers(this, "forecastfox-manager", "startUpdate");
  564.          
  565.     //check if we need to come from server
  566.     this._updateData["server"] = this._checkServer();
  567.  
  568.     //clear last error
  569.     this._error.init(SEVERITY_INFO, "", "");
  570.     
  571.     //parse from cache
  572.     if (!this._updateData["server"]) {
  573.       var success = this.parser.parseCache(this._getCache());
  574.       this._finishUpdate(success);
  575.     
  576.     //request from server
  577.     } else {
  578.  
  579.       //create the xml request
  580.       var comp = this;
  581.       this._updateRequest = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
  582.                             createInstance(Ci.nsIXMLHttpRequest);
  583.       this._updateRequest.overrideMimeType("text/xml; charset=iso-8859-1");
  584.       this._updateRequest.onerror = function() { comp._onRequestLoad(); };            
  585.       this._updateRequest.onload = function() { comp._onRequestLoad(); };            
  586.       this._updateRequest.open("GET", this._getServer(), true); 
  587.       
  588.       //set the channel bypass cache flag  
  589.       this._updateRequest.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
  590.       
  591.       //set the channel priority
  592.       if ("nsISupportsPriority" in Ci) {
  593.         if (this._updateRequest.channel instanceof Ci.nsISupportsPriority)
  594.           this._updateRequest.channel.priority = Ci.nsISupportsPriority.
  595.                                                     PRIORITY_LOWEST;                 
  596.       }
  597.     
  598.       //send the request and start the error timer (40 seconds)
  599.       this._errorTimer.init(this, ONE_MINUTE, Ci.nsITimer.TYPE_ONE_SHOT);
  600.       this._updateRequest.send(null);
  601.     }
  602.   },
  603.   
  604.   /**
  605.    * End a data update.
  606.    */ 
  607.   _endUpdate: function ManagerService__endUpdate()
  608.   {
  609.     //do nothing if not updating
  610.     if (!this.isUpdating)
  611.       return;
  612.     
  613.     //stop the alert timer
  614.     if (this._alertTimer)
  615.       this._alertTimer.cancel();
  616.           
  617.     //stop the error timer
  618.     if (this._errorTimer)
  619.       this._errorTimer.cancel();
  620.     
  621.     //stop the update timer
  622.     if (this._updateTimer)
  623.       this._updateTimer.cancel();
  624.  
  625.     //stop the serialize timer
  626.     if (this._serializeTimer)
  627.       this._serializeTimer.cancel();
  628.       
  629.     //mark that we are done updating
  630.     this._isUpdating = false;
  631.               
  632.     //cancel pending persist
  633.     if (this._radarPersist) {
  634.       this._radarPersist.cancelSave();
  635.       this._radarPersist.progressListener = null;
  636.       this._radarPersist = null;
  637.       this._radarFile = null;
  638.     }
  639.     
  640.     //cancel pending request
  641.     if (this._updateRequest) {
  642.       this._updateRequest.abort();
  643.       this._updateRequest.onload = null;
  644.       this._updateRequest.onerror = null;
  645.       this._updateRequest = null;
  646.     }
  647.         
  648.     //notify observers
  649.     if (this._obSvc)
  650.       this._obSvc.notifyObservers(this, "forecastfox-manager", "endUpdate");
  651.   },
  652.   
  653.   /**
  654.    * Callback from the xml request.
  655.    */
  656.   _onRequestLoad: function ManagerService__onRequestLoad()
  657.   {
  658.     //stop the error timer
  659.     this._errorTimer.cancel();
  660.     
  661.     //get error values
  662.     const PREFIX = "ff.manager.";
  663.     var name = "";
  664.     var message = "";
  665.       
  666.     //check if we actual received anything
  667.     if (this._updateRequest.responseText == "") {
  668.       name = this.bundle.GetStringFromName(PREFIX + "connect.name");
  669.       message = this.bundle.GetStringFromName(PREFIX + "connect.message");
  670.       this._error.init(SEVERITY_ERROR, name, message);
  671.       this._finishUpdate(false);
  672.       return; 
  673.     }
  674.                  
  675.     //get the request status
  676.     var status = -1;
  677.     try {
  678.       status = this._updateRequest.status;
  679.     } catch (e) {}
  680.  
  681.     
  682.     //check the status  
  683.     switch (status) {
  684.     
  685.     //no error  
  686.     case 200:
  687.       break;
  688.           
  689.     //authentication error
  690.     case 407:
  691.       name = this.bundle.GetStringFromName(PREFIX + "auth.name");
  692.       message = this.bundle.GetStringFromName(PREFIX + "auth.message");
  693.       this._error.init(SEVERITY_ERROR, name, message);
  694.       this._finishUpdate(false);
  695.       return; 
  696.  
  697.     //connection error
  698.     case -1:
  699.       name = this.bundle.GetStringFromName(PREFIX + "connect.name");
  700.       message = this.bundle.GetStringFromName(PREFIX + "connect.message");
  701.       this._error.init(SEVERITY_ERROR, name, message);
  702.       this._finishUpdate(false);
  703.       return; 
  704.       
  705.     //network error
  706.     default:
  707.       name = this.bundle.GetStringFromName(PREFIX + "net.name");
  708.       message = this.bundle.formatStringFromName(PREFIX + "net.message",
  709.                                                  [status], 1);
  710.       this._error.init(SEVERITY_ERROR, name, message);
  711.       this._finishUpdate(false);
  712.       return;   
  713.    } 
  714.    
  715.    //parse the document
  716.    var dom = this._updateRequest.responseXML;
  717.    var success = this.parser.parseDOM(dom);
  718.  
  719.    //save the expires information - default to 15 minutes
  720.    var expires = (new Date()).getTime() + (15*ONE_MINUTE);
  721.    this._updateData["expires"] = expires;
  722.    
  723.    //clear the request
  724.    this._updateRequest.onload = null;
  725.    this._updateRequest.onerror = null;
  726.    this._updateRequest = null;
  727.    
  728.    //finish the update if not successful 
  729.    if (!success)
  730.      this._finishUpdate(success);
  731.    
  732.    //otherwise fire the serialize timer
  733.    this._serializeTimer.init(this, DEFAULT_DELAY, Ci.nsITimer.TYPE_ONE_SHOT);  
  734.   },
  735.   
  736.   /** 
  737.    * Do function required once an update has completed.
  738.    *
  739.    * @param   Success code from parsing or serializing cache.
  740.    */
  741.   _finishUpdate: function ManagerService__finishUpdate(aSuccess)
  742.   {
  743.     //update was not successful
  744.     if (!aSuccess) {
  745.     
  746.       //force from server next time
  747.       this._updateData["force"] = true;
  748.       
  749.       //set the error if it has not been set
  750.       var err = this.lastError;
  751.       if (err.severity == SEVERITY_INFO) {
  752.         err = this.parser.lastError;
  753.         this._error.init(err.severity, err.name, err.message); 
  754.       }
  755.       
  756.     //update was successful
  757.     } else {
  758.     
  759.       //remove the force for next time
  760.       this._updateData["force"] = false;
  761.       
  762.       //update was from the server
  763.       if (this._updateData["server"]) {
  764.       
  765.         //save the update data
  766.         this._saveData();
  767.       
  768.         //set the alert slider on a 1 second delay
  769.         if (checkAlertService())
  770.           this._alertTimer.init(this, ONE_SECOND, Ci.nsITimer.TYPE_ONE_SHOT); 
  771.       }
  772.       
  773.       //check if we need to get the radar
  774.       if (this._checkRadar()) {
  775.         this._startRadar();
  776.         return;
  777.       }
  778.     }
  779.           
  780.     //mark the update is complete
  781.     this._isUpdating = false;
  782.     
  783.     //notify observers
  784.     this._obSvc.notifyObservers(this, "forecastfox-manager", "endUpdate");
  785.     
  786.     //schedule the next update
  787.     this._scheduleTimer();   
  788.   },
  789.   
  790.   /**
  791.    * Serialize the cache data to disk.
  792.    */
  793.   _serializeCache: function ManagerService__serializeCache()
  794.   {
  795.     //serialize data to disk
  796.     var success = this.parser.serializeCache(this._getCache());
  797.     
  798.     //finish the update process
  799.     this._finishUpdate(success);
  800.   },
  801.   
  802.   /**
  803.    * Check if the location id is set.
  804.    *
  805.    * @return  True if location is set otherwise false.
  806.    */
  807.   _checkID: function ManagerService__checkID()
  808.   {
  809.     //get the location id
  810.     var locid = this._updateData["general.locid"];
  811.       
  812.     //if the locid hasn't been set yet, prompt for it
  813.     var url = "chrome://forecastfox/content/options/options.xul";
  814.     if (locid == "00000" || locid == "") {
  815.       
  816.       //focus the options window if already open
  817.       var mediator = Cc['@mozilla.org/appshell/window-mediator;1'].
  818.                      getService(Ci.nsIWindowMediator);
  819.       var options = mediator.getMostRecentWindow("forecastfox:options");
  820.       if (options)
  821.         options.focus();
  822.       
  823.       //open a new options window
  824.       else    
  825.         getTopWindow().openDialog(url, "options", "chrome,modal");
  826.         
  827.       //return failed    
  828.       return false; 
  829.     }
  830.     
  831.     //return success
  832.     return true;
  833.   },    
  834.  
  835.   /**
  836.    * Check if the data needs to come from the server.
  837.    *
  838.    * @return  True or False.
  839.    */   
  840.   _checkServer: function ManagerService__checkServer()
  841.   {
  842.     //check if forced
  843.     if (this._updateData["force"])
  844.       return true;
  845.       
  846.     //check the cache
  847.     if (!this._checkCache())
  848.       return true;
  849.       
  850.     //get the current date/time
  851.     var current = (new Date()).getTime();
  852.     
  853.     //get the delay and make sure it is greater than 0;
  854.     var delay = this._updateData["general.delay"];
  855.     if (delay < 0)
  856.       delay = 30;
  857.       
  858.     //determine the next update time
  859.     var last = Number(this._updateData["general.last"]);
  860.     var next = last + (delay*ONE_MINUTE);
  861.  
  862.     //check if the last update occurred in the future
  863.     if (last > current)
  864.       return true;
  865.       
  866.     //check if it has been the allowed time
  867.     if (((next - current) <= DEFAULT_DELAY))
  868.       return true;
  869.       
  870.     //from cache
  871.     return false;
  872.   },
  873.   
  874.   /**
  875.    * Check if the data can come from the cache.
  876.    *
  877.    * @return  True if the cache file exists.
  878.    */     
  879.   _checkCache: function ManagerService__checkCache()
  880.   {
  881.     var file = this._getCache();
  882.     if (!file.exists())
  883.       return false;
  884.     return true;
  885.   },
  886.   
  887.   /**
  888.    * Check if we need to get the radar image.
  889.    *
  890.    * @return  True if the radar image is required.
  891.    */
  892.   _checkRadar: function ManagerService__checkRadar()
  893.   {
  894.     //check if the panel is enabled
  895.     if (!this._updateData["radar.panel.enabled"])
  896.       return false;
  897.       
  898.     //check if there is a url for the radar
  899.     var URL = this.parser.getValue("radar", 0, "imagelarge", null);
  900.     if (!URL || URL == "N/A")
  901.         URL = this.parser.getValue("radar", 0, "image", null);
  902.     if (!URL || URL == "N/A")
  903.       return false;
  904.     
  905.     //check if the file exists
  906.     var name = "radar-" + this._updateData["profile.current"] + ".gif";
  907.     var file = this.disk.get(name, TYPE_CACHE);
  908.     if (!file.exists())
  909.       return true;
  910.         
  911.     //check the radar last
  912.     if (Number(this._updateData["general.radar"]) >
  913.         Number(this._updateData["general.last"]))
  914.       return false;
  915.       
  916.     //we need radar
  917.     return true;
  918.   },
  919.   
  920.   /**
  921.    * Get the update data from preferences.
  922.    */
  923.   _getData: function ManagerService__getData()
  924.   {
  925.     //create the data object
  926.     var data = {};
  927.     
  928.     //set its properties
  929.     data["profile.current"] = getPref("profile.current");
  930.     data["general.last"] = getPref("general.last");
  931.     data["general.locid"] = getPref("general.locid");
  932.     data["general.delay"] = getPref("general.delay");
  933.     data["general.radar"] = getPref("general.radar");
  934.     data["units.current"] = getPref("units.current");
  935.     data["radar.panel.enabled"] = getPref("radar.panel.enabled");
  936.     
  937.     data["server"] = true;
  938.     data["force"] = false;
  939.     data["expires"] = null;
  940.     
  941.     //return the data object
  942.     return data;
  943.   },
  944.       
  945.   /**
  946.    * Build the update server url.
  947.    *
  948.    * @return  The url used in the xml request.
  949.    */
  950.   _getServer: function ManagerService__getServer()
  951.   {
  952.     var URL = "http://forecastfox.accuweather.com/adcbin/forecastfox/weather_data.asp?";
  953.     URL += "location=" + this._updateData["general.locid"];
  954.  
  955.     //set units
  956.     URL += "&metric=" + this._updateData["units.current"];
  957.     
  958.     //add partner  
  959.     URL += "&partner=" + this.partner;
  960.     
  961.     //return string
  962.     return URL;
  963.   },
  964.   
  965.   /**
  966.    * Get the feed cache file.
  967.    *
  968.    * @return  A object implementing the nsIFile interface.
  969.    */
  970.   _getCache: function ManagerService__getCache()
  971.   {
  972.     var name = "feed-" + this._updateData["profile.current"] + ".js";  
  973.     return this.disk.get(name, TYPE_CACHE);
  974.   },
  975.   
  976.   /**
  977.    * Save the update data to preferences.
  978.    */
  979.   _saveData: function ManagerService__saveData()
  980.   {
  981.     //set a new delay if we have the expires property
  982.     var current = (new Date()).getTime();
  983.     if (this._updateData["expires"] != null) {
  984.     
  985.       //get the next time
  986.       var next = this._updateData["expires"];
  987.       
  988.       //get the delay
  989.       var delay = (next-current)/(ONE_MINUTE);
  990.       
  991.       //add a random number of minutes to it
  992.       var random = 1 + Math.random()*2;
  993.       delay = Math.floor(delay + random);
  994.       
  995.       //make sure the delay is rational
  996.       if (delay > -5 && delay <= 0)
  997.         delay = 5;
  998.       if (delay < 0 || delay > 30)
  999.         delay = 30;
  1000.  
  1001.       //save the delay and clear the expires
  1002.       this._updateData["general.delay"] = delay;
  1003.       this._updateData["expires"] = null;
  1004.     }
  1005.     
  1006.     //set the last property
  1007.     this._updateData["general.last"] = String(current);
  1008.     
  1009.     //set the preferences
  1010.     this._isLoading = true;
  1011.     setPref("general.last", this._updateData["general.last"]);
  1012.     setPref("general.delay", this._updateData["general.delay"]); 
  1013.     this._isLoading = false;
  1014.   },
  1015.     
  1016.   /**
  1017.    * Start the radar update.
  1018.    */
  1019.   _startRadar: function ManagerService__startRadar()
  1020.   {
  1021.     //get the radar url
  1022.     var URL = this.parser.getValue("radar", 0, "imagelarge", null);
  1023.     if (!URL || URL == "N/A")
  1024.         URL = this.parser.getValue("radar", 0, "image", null);
  1025.     
  1026.     //convert the url to a uri
  1027.     var ioSvc = Cc["@mozilla.org/network/io-service;1"].
  1028.                 getService(Ci.nsIIOService);
  1029.     var URI = ioSvc.newURI(URL, null, null);  
  1030.     
  1031.     //get a temp file to persist to  
  1032.     var name = "radar-" + this._updateData["profile.current"] + ".gif";  
  1033.     this._radarFile = this.disk.get(name, TYPE_TEMP);
  1034.  
  1035.     //setup the persist object
  1036.     var flags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE | 
  1037.                 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
  1038.     this._radarPersist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
  1039.                          createInstance(Ci.nsIWebBrowserPersist);              
  1040.     this._radarPersist.persistFlags |= flags;
  1041.     this._radarPersist.progressListener = this;
  1042.     this._radarPersist.saveURI(URI, null, null, null, null, this._radarFile); 
  1043.   },
  1044.   
  1045.   /**
  1046.    * End the radar update
  1047.    */
  1048.   _endRadar: function ManagerService__endRadar()
  1049.   {   
  1050.     //copy the file to correct location
  1051.     var name = "radar-" + this._updateData["profile.current"] + ".gif";    
  1052.     var file = this.disk.get(name, TYPE_CACHE);
  1053.     this.disk.copy(this._radarFile, file);
  1054.  
  1055.     //evict the image from the cache
  1056.     var URL = this.disk.getFileURL(this._radarFile);
  1057.     this.evictImage(URL);
  1058.     
  1059.     //remove the old file
  1060.     try {
  1061.       removeFile(this._radarFile);
  1062.     } catch(e) {}
  1063.     
  1064.     //save the radar time
  1065.     this._isLoading = true;
  1066.     var current = String((new Date()).getTime());
  1067.     this._updateData["general.radar"] = current;
  1068.     setPref("general.radar", current);
  1069.     this._isLoading = false;
  1070.     
  1071.     //clear the persist
  1072.     this._radarFile = null;
  1073.     this._radarPersist.progressListener = null;
  1074.     this._radarPersist = null;
  1075.      
  1076.     //mark update finished
  1077.     this._isUpdating = false;  
  1078.      
  1079.     //notify front-end
  1080.     this._obSvc.notifyObservers(this, "forecastfox-manager", "endUpdate");  
  1081.     
  1082.     //schedule the next update
  1083.     this._scheduleTimer();      
  1084.   },
  1085.   
  1086.   /**
  1087.    * Start the alert slider.
  1088.    */
  1089.   _startAlert: function ManagerService__startAlert()
  1090.   {
  1091.     //always increment count for cc when called
  1092.     var count = getPref("cc.slider.count");
  1093.     setPref("cc.slider.count", count + 1);
  1094.       
  1095.     //determine if a swa is active
  1096.     var active = false;
  1097.     if (this.parser.getValue("swa", 0, "active", null) == "true")
  1098.       active = true;
  1099.  
  1100.     //if active determine if we should show it
  1101.     var enabled = false;
  1102.     var freq = 0;
  1103.     if (active) {
  1104.     
  1105.       //always increment count for swa if active
  1106.       count = getPref("swa.slider.count");
  1107.       setPref("swa.slider.count", count + 1);
  1108.       
  1109.       //show swa
  1110.       enabled = getPref("swa.slider.enabled");
  1111.       freq = getPref("swa.slider.freq");    
  1112.       if (enabled && count == 1) {
  1113.         this._endAlert("swa");
  1114.         return;
  1115.       }
  1116.       
  1117.       //reset the count to 1
  1118.       if (count >= freq)
  1119.         setPref("swa.slider.count", 1);
  1120.     } else
  1121.       setPref("swa.slider.count", 1);
  1122.  
  1123.     
  1124.     //show current
  1125.     enabled = getPref("cc.slider.enabled");
  1126.     freq = getPref("cc.slider.freq");     
  1127.     if (enabled && count >= freq) {
  1128.       setPref("cc.slider.count", 1);
  1129.       this._endAlert("cc");
  1130.     }
  1131.   },
  1132.   
  1133.   /**
  1134.    * Actually show the required alert slider.
  1135.    *
  1136.    * @param   The prefix of the item to show.
  1137.    */
  1138.   _endAlert: function ManagerService__endAlert(aPrefix)
  1139.   {
  1140.     //get the parser target
  1141.     var target = (aPrefix == "cc") ? "current" : "swa";
  1142.  
  1143.     //get the current icon pack
  1144.     var pack = this.icons.current;   
  1145.     var parser = this.parser;
  1146.     
  1147.     //get the display options
  1148.     var display = getPref(aPrefix + ".slider.display");
  1149.     var title = getPref(aPrefix + ".slider.title");
  1150.     var label = getPref(aPrefix + ".slider.label");  
  1151.     var icon = parser.getValue(target, 0, "icon", null);
  1152.     var url = parser.getValue(target, 0, "url", null);
  1153.     
  1154.     switch (display) {
  1155.     
  1156.     //only show icons
  1157.     case 0:
  1158.       icon = pack.getItem(icon + "-large").URL;
  1159.       title = "";
  1160.       label = "";
  1161.       break;
  1162.       
  1163.     //only show text
  1164.     case 1:
  1165.       icon = "";
  1166.       title = parser.getLabel(title, target, 0);
  1167.       label = parser.getLabel(label, target, 0);
  1168.       break;
  1169.       
  1170.     //show both
  1171.     case 2:
  1172.       icon = pack.getItem(icon + "-large").URL;
  1173.       title = parser.getLabel(title, target, 0);
  1174.       label = parser.getLabel(label, target, 0);
  1175.       break;
  1176.     }
  1177.  
  1178.     //do alert  
  1179.     var alSvc = Cc["@mozilla.org/alerts-service;1"].
  1180.                 getService(Ci.nsIAlertsService);
  1181.     var cookie = [icon, url].toSource();            
  1182.     alSvc.showAlertNotification(icon, title, label, true, cookie, this);
  1183.   },
  1184.   
  1185.   /**
  1186.    * Schedule the update timer.
  1187.    * 
  1188.    * @param   The timer delay, override default times.
  1189.    */
  1190.   _scheduleTimer: function ManagerService__scheduleTimer(aOverride)
  1191.   {
  1192.     //cancel previous timer
  1193.     this._updateTimer.cancel();
  1194.     
  1195.     //use the override delay
  1196.     if (aOverride) {
  1197.       this._updateTimer.init(this, aOverride, Ci.nsITimer.TYPE_ONE_SHOT);
  1198.       return;
  1199.     }
  1200.     
  1201.     //get our error status
  1202.     var delay = 0;
  1203.     var err = (this.lastError.severity == SEVERITY_INFO) ? false : true;
  1204.     
  1205.     //if not an error then schedule normal time
  1206.     if (!err) {
  1207.       delay = this._updateData["general.delay"]*ONE_MINUTE;
  1208.       this._updateError = 0;
  1209.       
  1210.     //error occurred from cache set delay to 10
  1211.     } else if (!this._updateData["server"]) {       
  1212.       delay = DEFAULT_DELAY;
  1213.       this._updateError = 0;
  1214.       
  1215.     //error occurred form server
  1216.     } else {
  1217.     
  1218.       //ten seconds for the first error
  1219.       if (this._updateError == 0) {
  1220.         delay = 10*ONE_SECOND;
  1221.         this._updateError++;
  1222.         
  1223.       //progressively more minutes with each additional error
  1224.       } else {
  1225.         delay = this._updateError*ONE_MINUTE;
  1226.         this._updateError++;
  1227.       }
  1228.     }
  1229.     
  1230.     //setup the timer
  1231.     this._updateTimer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT);
  1232.   },
  1233.  
  1234.   /**
  1235.    * Retrieve a service from our services object.
  1236.    *
  1237.    * @param   Name of the service.
  1238.  
  1239.    * @return  The requested service and interface.
  1240.    */
  1241.   _getService: function ManagerService__getService(aName)
  1242.   {
  1243.     //get the service
  1244.     var contractID = gComponents[aName].contractID;
  1245.     var interfaceID = gComponents[aName].interfaceID;  
  1246.     var service = Cc[contractID].getService(interfaceID);
  1247.  
  1248.     var prompter = getPrompter(getTopWindow());
  1249.     try {
  1250.     
  1251.       //check if service has been started before
  1252.       if (!this._services.hasOwnProperty(aName))
  1253.         this._services[aName] = service.start();
  1254.         
  1255.       //service did not start successfully
  1256.       if (!this._services[aName]) {
  1257.         var err = service.lastError;
  1258.         this.disk.log("The following service: " + aName + " returned an error: " + err.toString(), null, null);
  1259.         prompter.alert(err.name, err.message);
  1260.         delete this._services[aName];
  1261.         return null;
  1262.       }
  1263.  
  1264.  
  1265.       //return the service
  1266.       return service;
  1267.             
  1268.     //service threw an error
  1269.     } catch (e) {
  1270.         this.disk.log("Error starting the following service: " + aName, e, null);
  1271.         prompter.alert(e.name, e.message);
  1272.         delete this._services[aName];
  1273.     }
  1274.     
  1275.     //service not started successfully
  1276.     return null;
  1277.   }
  1278. };